﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Emico.Linq.Criterion.Serialization;

namespace Emico.Linq.Criterion
{
    [Serializable]
    public class OrderBy<T> : IOrderBy<T>
        where T : class
    {
        #region Variables

        #endregion

        #region Properties

        public ListSortDirection SortDirection
        {
            get;
            private set;
        }

        public string PropertyName
        {
            get;
            private set;
        }

        #endregion

        #region Constructors

        public OrderBy(string propertyName, ListSortDirection sortDirection = ListSortDirection.Ascending)
        {
            if (string.IsNullOrWhiteSpace(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }

            this.PropertyName = propertyName;
            this.SortDirection = sortDirection;
        }

        public OrderBy(string propertyName, bool ascending)
            : this(propertyName, ascending ? ListSortDirection.Ascending : ListSortDirection.Descending)
        {
        }
        
        public OrderBy(Expression<Func<T, object>> selector, ListSortDirection sortDirection = ListSortDirection.Ascending)
            : this(new PropertyPathVisitor().GetPropertyPath(selector), sortDirection == ListSortDirection.Ascending)
        {
        }
        
        public OrderBy(Expression<Func<T, object>> selector, bool ascending)
            : this(selector, ascending ? ListSortDirection.Ascending : ListSortDirection.Descending)
        {
        }

        protected OrderBy(SerializationInfo info, StreamingContext context)
        {
            this.SortDirection = (ListSortDirection)info.GetValue("SortDirection", typeof(ListSortDirection));
            this.PropertyName = info.GetString("PropertyName");
        }

        #endregion

        #region Implement IOrder
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("SortDirection", this.SortDirection);
            info.AddValue("PropertyName", this.PropertyName);
        }

        public Expression ToLinqExpression(Criteria<T> criteria, ParameterExpression parameter)
        {
            Expression param = ExpressionHelper.CrateNestExpressionProperty<T>(this.PropertyName, parameter);
            return param;
        }

        #endregion
    }
}
